package worldwind.kml;

import gov.nasa.worldwind.BasicModel;
import gov.nasa.worldwind.Model;
import gov.nasa.worldwind.awt.WorldWindowGLJPanel;
import gov.nasa.worldwind.event.SelectEvent;
import gov.nasa.worldwind.event.SelectListener;
import gov.nasa.worldwind.geom.Angle;
import gov.nasa.worldwind.geom.LatLon;
import gov.nasa.worldwind.geom.Position;
import gov.nasa.worldwind.geom.Sector;
import gov.nasa.worldwind.layers.CompassLayer;
import gov.nasa.worldwind.layers.WorldMapLayer;
import gov.nasa.worldwind.layers.Earth.BMNGSurfaceLayer;
import gov.nasa.worldwind.layers.Earth.LandsatI3;
import gov.nasa.worldwind.render.WWIcon;
import gov.nasa.worldwind.util.BasicDragger;
import gov.nasa.worldwind.util.StatusBar;
import gov.nasa.worldwind.view.orbit.BasicOrbitView;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;

import javax.swing.AbstractAction;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;

import worldwind.kml.model.KMLFile;
import worldwind.kml.model.KMLPlacemark;
import worldwind.kml.tree.DocListTreeNode;
import worldwind.kml.tree.KMLDocTreeNode;
import worldwind.kml.tree.KMLTreeView;
import worldwind.kml.tree.Sectored;
import worldwind.kml.ui.InfoDialog;


/**
 * Created by IntelliJ IDEA.
 * User: tgleason
 * Date: Oct 17, 2008
 * Time: 11:53:05 PM
 * To change this template use File | Settings | File Templates.
 */
public class KMLViewer extends JFrame {
    StatusBar statusBar;
    JLabel cursorPositionDisplay;
    WorldWindowGLJPanel wwd;
    DocListTreeNode docList = new DocListTreeNode();
    KMLTreeView tree;
    JSplitPane splitPane;
    DefaultTreeModel treeModel;
    URL iconURL;



    public KMLViewer() throws HeadlessException {
        super("KML Viewer");

        setLayout(new BorderLayout());

        //--  Worldwind
        wwd = new WorldWindowGLJPanel();
        wwd.setPreferredSize(new Dimension(1000, 600));

        //--  KLUDGE: for some reason the GLJPanel doesn't get focus when clicked
        wwd.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                wwd.grabFocus();
            }

            public void mouseEntered(MouseEvent e) {
                wwd.grabFocus();
            }
        });


        //--  Create a JTree
        treeModel = new DefaultTreeModel(docList);
        tree = new KMLTreeView(wwd, treeModel);
        tree.setRootVisible(false);
        tree.setShowsRootHandles(true);


        //--  Double-click on a node in the tree and we'll try to zoom to it.
        //--  This doesn't work too well yet (and doesn't work on folder nodes)
        tree.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                if (e.getClickCount() == 2) {
                    TreePath path = tree.getPathForLocation(e.getX(), e.getY());
                    if (path == null)
                        return;
                    Object obj = path.getLastPathComponent();
                    if (obj instanceof Sectored) {
                        zoomToSector (((Sectored)obj).getSector());
                    }
                }
            }
        });

        //--  Set up a split view and put the tree on the left
        JSplitPane splitter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
                new JScrollPane(tree), wwd);
        splitter.setContinuousLayout(true);
        splitter.setDividerSize(3);
        splitter.setDividerLocation(300);
        this.getContentPane().add(splitter, java.awt.BorderLayout.CENTER);

        this.statusBar = new StatusBar();
        this.getContentPane().add(statusBar, BorderLayout.PAGE_END);
        this.statusBar.setEventSource(wwd);


        this.pack();

        //--  Set up some layers
        Model m = new BasicModel();
        m.getLayers().clear();
        m.getLayers().add(new BMNGSurfaceLayer());

        LandsatI3 lsi3 = new LandsatI3();
        lsi3.setDrawBoundingVolumes(false);
        lsi3.setOpacity(1);
        m.getLayers().add(lsi3);

        m.getLayers().add(new CompassLayer());
        m.getLayers().add(new WorldMapLayer());

        m.setShowWireframeExterior(false);
        m.setShowWireframeInterior(false);
        wwd.setModel(m);

        wwd.grabFocus();

        //--  Set up the menu bar
        JMenuBar menuBar = new JMenuBar();

        JMenu menu = new JMenu("File");
        menu.add(new JMenuItem(new AbstractAction("Open File...") {
            public void actionPerformed(ActionEvent ae) {
                openFile();
            }
        }));

        menu.add(new JMenuItem(new AbstractAction("Open URL...") {
            public void actionPerformed(ActionEvent ae) {
                openURL();
            }
        }));

        menu.addSeparator();

        JMenu samplesMenu = new JMenu("Samples");
        
        samplesMenu.add(new SampleFileAction("KML Samples", "http://code.google.com/apis/kml/documentation/KML_Samples.kml"));
        //http://bbs.keyhole.com/ubb/placemarks/521519-Vancouver.kmz
        samplesMenu.add(new SampleFileAction("Vancouver 3D", "http://bbs.keyhole.com/ubb/placemarks/521519-Vancouver.kmz"));
        samplesMenu.add(new SampleFileAction("Appalachian Trail", "http://bbs.keyhole.com/ubb/download.php?Number=1114687"));
        samplesMenu.add(new SampleFileAction("World Heritage Sites", "http://whc.unesco.org/p_dynamic/sites/whc-en.kmz"));
        samplesMenu.add(new SampleFileAction("Inca Trail", "http://www.jqjacobs.net/archaeo/sites/machu_picchu.kmz"));

        //TODO: Support: http://wikiloc.com/wikiloc/geoServer.do?format=kml&id=190160

        menu.add(samplesMenu);

        menuBar.add(menu);

        setJMenuBar(menuBar);


        //--  Listen for Point selections:
        wwd.addSelectListener(new SelectListener()
        {
            private WWIcon lastToolTipIcon = null;
            private BasicDragger dragger = new BasicDragger(wwd);

            public void selected(SelectEvent event)
            {
                if (event.getEventAction().equals(SelectEvent.LEFT_CLICK))
                {
                    Object obj = event.getTopObject();
                    if (obj != null && obj instanceof KMLPlacemark) {
                        displayInfoPane((KMLPlacemark) obj);
                    }
                }
            }
        });


    }

    private void displayInfoPane(KMLPlacemark kmlPlacemark) {
        if (kmlPlacemark.getDescription() != null) {
            new InfoDialog(this, "<html>" + kmlPlacemark.getDescription() + "</html>");
        }

    }

    class SampleFileAction extends AbstractAction {
        String urlStr;
        String name;
        SampleFileAction(String name, String url) {
            super(name);
            this.urlStr = url;
            this.name = name;
        }

        public void actionPerformed(ActionEvent ae) {
            URL url = null;
            try {
                url = new URL(urlStr);
            } catch (MalformedURLException e) {
                JOptionPane.showMessageDialog(KMLViewer.this, "Not a valid URL: " + e.getMessage());
            }

            if (url != null) {
                try {
                    KMLFile kml = KMLParser.parseURL(url);
                    addKMLLayer(kml, name);
                    zoomToSector(kml.getSector());
                } catch (Exception e) {
                    JOptionPane.showMessageDialog(KMLViewer.this, "Error: " + e.getMessage());
                }
            }
        }
    }

    private void openURL() {
        String urlStr = JOptionPane.showInputDialog("KML/KMZ URL:");

        if (urlStr == null)
            return;

        URL url = null;

        try {
            url = new URL(urlStr);
        } catch (MalformedURLException e) {
            JOptionPane.showMessageDialog(this, "Not a valid URL: " + e.getMessage());
        }

        if (url != null) {
            try {
                KMLFile kml = KMLParser.parseURL(url);
                addKMLLayer(kml, url.toString());
                zoomToSector(kml.getSector());
            } catch (Exception e) {
                JOptionPane.showMessageDialog(this, "Error: " + e.getMessage());
            }
        }
    }

    private void openFile () {
        JFileChooser chooser = new JFileChooser();
        if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
            File f = chooser.getSelectedFile();
            try {
                KMLFile kml = KMLParser.parseFile(f.getAbsolutePath());
                addKMLLayer(kml, f.getName());
                zoomToSector(kml.getSector());
            } catch (Exception e) {
                JOptionPane.showMessageDialog(this, "Error: " + e.getMessage());
            }
        }
    }

    private void addKMLLayer (KMLFile kml, String name) {
        KMLLayer kmlLayer = new KMLLayer(kml);
        wwd.getModel().getLayers().add(kmlLayer);
        docList.add(new KMLDocTreeNode(kml, name, kmlLayer));
        treeModel.nodeStructureChanged(docList);
    }


    //--  TODO:  This /rotates/ to the sector, but just zooms to a fixed level.  Need to
    //--  calculate the zoom factor from the sector size (somehow)
    private void zoomToSector(Sector s) {
        if (s == null){
            //System.out.println("Null sector");
            return;
        }

        BasicOrbitView view = (BasicOrbitView)wwd.getView();

        LatLon latLon = new LatLon(Angle.average(s.getMinLatitude(), s.getMaxLatitude()), Angle.average(s.getMinLongitude(), s.getMaxLongitude()));
        
        // Stop all animations on the view, and start a 'pan to' animation.		
        view.stopAnimations();
		view.addPanToAnimator(new Position(latLon, 0), view.getHeading(), view.getPitch(), 100000);
    }

    public static void main(String[] args) {
        if (gov.nasa.worldwind.Configuration.isMacOS())
        {
            System.setProperty("apple.laf.useScreenMenuBar", "true");
            System.setProperty("com.apple.mrj.application.apple.menu.about.name", "World Wind AWT Canvas App");
            System.setProperty("com.apple.mrj.application.growbox.intrudes", "false");
        }

        KMLViewer viewer = new KMLViewer();
        viewer.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        viewer.setVisible(true);
    }

}
